package storage

import (
	"bufio"
	"crypto/sha256"
	"fmt"
	"goDFS/etc"
	"goDFS/public"
	"io"
	"os"
	"path"
	"regexp"
)

//这里定义文件hush，以及令牌生成，令牌解析到地址

type FileKey struct {
	Hash   string //源文件hush
	Group  string //储存组
	En1    string //储存地址1
	En2    string //储存地址2
	Name   string //文件名
	Key    string //文件令牌
	Extend string //文件扩展名
}

//生成令牌
func (k *FileKey) CreateKey() {
	s := k.Hash
	k.Group = "group"
	k.En1 = s[60:62]
	k.En2 = s[62:64]
	k.Name = s[0:32]

	k.Key = fmt.Sprintf("group:%s:path:%s/%s:%s%s", k.Group, k.En1, k.En2, k.Name, k.Extend)

}

//获取文件地址
func (k *FileKey) GetPath(conf *etc.Conf) string {
	storageConf := conf.GetStorage()
	return fmt.Sprintf("%s/%s/%s/%s/%s%s", storageConf.GroupPath, k.Group, k.En1, k.En2, k.Name, k.Extend)
}

//根据令牌保存文件
func (k *FileKey) SaveFile(data []byte, conf *etc.Conf) error {
	getPath := k.GetPath(conf)

	_, err := os.Stat(getPath)
	if err == nil {
		return nil
	}

	f, err := os.Create(getPath)
	if err != nil {
		etc.SaveLog("[ SaveFile ]"+err.Error(), 2)
		return err
	}
	defer f.Close()
	_, err = f.Write(data)
	if err != nil {
		return err
	}

	return nil

}

//根据令牌读取文件
func (k *FileKey) ReadFile(conf *etc.Conf) ([]byte, error) {
	src := k.GetPath(conf)
	f, err := os.Open(src)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	buf := make([]byte, 1024)
	fileBuf := make([]byte, 0, 1024)
	bf := bufio.NewReader(f)

	for {
		n, err := bf.Read(buf)
		fileBuf = append(fileBuf, buf[:n]...)

		if err != nil { //遇到任何错误立即返回，并忽略 EOF 错误信息
			if err == io.EOF {
				return fileBuf, nil
			}
			return nil, nil
		}
	}

}

//计算hush
func calculateHash(data []byte) string {
	enc := sha256.Sum256(data)
	return fmt.Sprintf("%x", enc)
}

//计算文件令牌  （文件内容， 文件名）
func NewFileKey(data []byte, fileName string) *FileKey {
	key := new(FileKey)
	key.Hash = calculateHash(data)
	key.Extend = path.Ext(fileName)
	key.CreateKey()
	return key

}

//令牌格式：group:group:path:48/61:ea6abe1d432ca41456f8d8697a0d0697.json
//根据令牌，创建一个FileKey，无Rand和Hash
func TokenToFileKey(token string) (*FileKey, error) {
	groupRegexp := regexp.MustCompile(`^group:(.*?):path:(.*?)/(.*?):(.*?)\.(.*)`)
	params := groupRegexp.FindStringSubmatch(token)

	if len(params) < 1 {
		return nil, public.NewError(public.AnalysisTokenErr, 0, token)
	}

	params = params[1:]

	if len(params) < 5 {
		return nil, public.NewError(public.AnalysisTokenErr, 0, token)
	}

	fileKey := &FileKey{
		Group:  params[0],
		En1:    params[1],
		En2:    params[2],
		Name:   params[3],
		Key:    token,
		Extend: fmt.Sprintf(".%s", params[4]),
	}

	return fileKey, nil
}

//不要写到init里，要根据配置文件改变的
//创建储存地址文件
func CreteMkdir(conf *etc.Storage) {
	path := fmt.Sprintf("%s/group/", conf.GroupPath)
	_ = os.Mkdir(path, os.ModePerm)
	var initDir = [16]string{"0", "1", "2", "3", "4", "5", "6", "7",
		"8", "9", "a", "b", "c", "d", "e", "f"}
	var pa []string
	for _, v1 := range initDir {
		for _, v2 := range initDir {
			pa = append(pa, v1+v2)
		}
	}
	for _, v1 := range pa {
		_ = os.Mkdir(path+v1, os.ModePerm)
		for _, v2 := range pa {
			_ = os.Mkdir(path+v1+"/"+v2, os.ModePerm)
		}
	}
}
